package service

import (
	"context"
	"fmt"
	"gcopyright/models"
	"gcopyright/repositories"
	"gcopyright/solcabi"
	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/accounts/keystore"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/ethclient"
	"github.com/ethereum/go-ethereum/rpc"
	"github.com/kataras/iris"
	"io/ioutil"
	"log"
	"math/big"
	"os"
	"strconv"
	"strings"
	"time"
)

// 获取目录下文件的名
func GetAllFile(pathname string, s []string) ([]string, error) {
	rd, err := ioutil.ReadDir(pathname)
	if err != nil {
		fmt.Println("read dir fail:", err)
		return s, err
	}
	for _, fi := range rd {
		if fi.IsDir() {
			fullDir := pathname + "/" + fi.Name()
			s, err = GetAllFile(fullDir, s)
			if err != nil {
				fmt.Println("read dir fail:", err)
				return s, err
			}
		} else {
			fullName := pathname + "/" + fi.Name()
			s = append(s, fullName)
		}
	}
	return s, nil
}

type Solservice struct {
	// 定义结构体
	ctx iris.Context
}

//0xd0430c2b023cfe16e373e85085464c33311fccb6
func NewSolService(c iris.Context) *Solservice {
	return &Solservice{ctx: c}
}
func ReadFile(filePth string) ([]byte, error) {
	f, err := os.Open(filePth)
	if err != nil {
		return nil, err
	}
	return ioutil.ReadAll(f)
}

// 获取文件夹下面的文件列表
func (s *Solservice) Ls() []string {
	files, _ := ioutil.ReadDir("F:\\ethereum\\genesis-block\\keystore")
	var array = make([]string, 0)
	for _, f := range files {
		array = append(array, f.Name())
	}
	return array
}

//查询区块链信息
func (s *Solservice) QuerToken(ad string) string {
	//创建基于IPC的RPC连接到远程节点
	conn, err := ethclient.Dial("\\\\.\\pipe\\geth.ipc")
	if err != nil {
		log.Fatalf("无法链接以太坊客户端: %v", err)
	}
	//实例化合同并显示其名称  // 0x7ea1878b139b1463a022ef5575a2801a5e57ca3a Qu Xiaogang
	token, err := solcabi.NewToken(common.HexToAddress(ad), conn)
	if err != nil {
		log.Println("无法实例化令牌合同:", err)
	}
	name, err := token.Name(nil)
	if err != nil {
		log.Println("无法检索令牌名称: ", err)
	}
	fmt.Println("Token name:", name)
	conn.Close()
	return name
}

//查询区块链信息 曲小刚
func (s *Solservice) QuerQuXiaoGang() string {
	conn, err := ethclient.Dial("\\\\.\\pipe\\geth.ipc")
	if err != nil {
		log.Fatalf("无法链接以太坊客户端: %v", err)
	}
	//实例化合同并显示其名称  // 0x7ea1878b139b1463a022ef5575a2801a5e57ca3a Qu Xiaogang
	token, err := solcabi.NewSolcabi(common.HexToAddress("0x7ea1878b139b1463a022ef5575a2801a5e57ca3a"), conn)
	if err != nil {
		log.Fatalf("无法实例化令牌合同: %v", err)
	}
	fmt.Println("捕捉到：", token.SolcabiTransactor)
	return "0000"

}

// 部署智能合约，每部署一次记录一次数据。
func (s *Solservice) Deploy(x int, hash string, table models.FileInfoTable, sql *repositories.RepositoriesSqlite) common.Address {
	var filePath string
	var hexaAddress string

	if x < 1 {
		filePath = "F:\\ethereum\\genesis-block\\keystore\\" + s.Ls()[0]
		hexaAddress = s.Accounts()[0]
	} else {
		filePath = "F:\\ethereum\\genesis-block\\keystore\\" + s.Ls()[x-1]
		hexaAddress = s.Accounts()[x]
	}
	key, err := ReadFile(filePath) //读取key
	if err != nil {
		log.Fatal("读取错误")
	}
	//创建基于IPC的RPC连接到远程节点和授权的交易者
	conn, err := ethclient.Dial("\\\\.\\pipe\\geth.ipc")
	if err != nil {
		log.Fatalf("Failed to connect to the Ethereum client: %v", err)
	}
	auth, err := bind.NewTransactor(strings.NewReader(string(key)), "0x0001")
	if err != nil {
		log.Fatalf("Failed to create authorized transactor: %v", err)
	}
	//部署一个新的合同
	address, tx, token, err := solcabi.DeployToken(auth, conn, new(big.Int), hash, 0, hexaAddress)
	if err != nil {
		log.Fatalf("无法部署新的令牌合同: %v", err)
	}
	fmt.Printf("合同待定部署: 0x%x\n", address)
	fmt.Printf("交易等待开采: 0x%x\n\n", tx.Hash())
	_, err = bind.WaitDeployed(context.Background(), conn, tx)
	name, err := token.Name(&bind.CallOpts{Pending: true})
	if err != nil {
		log.Fatalf("Failed to retrieve pending name: %v", err)
	}
	fmt.Println("Pending name:", name)
	conn.Close()

	t := strconv.FormatInt(time.Now().Unix(), 10)
	sql.InsertEtherTable(hexaAddress, fmt.Sprintf("%x", address), table.Title, table.Hash, t, "admin")
	return address
}

// 部署曲小刚智能合约，没部署一次记录一次数据。

func (s *Solservice) DeployQuXiaoGang() common.Address {
	key, err := ReadFile("F:\\ethereum\\genesis-block\\keystore\\UTC--2019-07-16T02-28-44.030567100Z--09d3146906c7f39347dd977d303ad36e2a1186f6") //读取key
	if err != nil {
		log.Fatal("读取错误")
	}
	//创建基于IPC的RPC连接到远程节点和授权的交易者
	conn, err := ethclient.Dial("\\\\.\\pipe\\geth.ipc")
	if err != nil {
		log.Fatalf("Failed to connect to the Ethereum client: %v", err)
	}
	auth, err := bind.NewTransactor(strings.NewReader(string(key)), "0x0001")
	if err != nil {
		log.Fatalf("Failed to create authorized transactor: %v", err)
	}

	//部署一个新的合同
	address, tx, _, err := solcabi.DeploySolcabi(auth, conn, "0xhhhhhhh", common.HexToAddress("0x09d3146906c7f39347dd977d303ad36e2a1186f6"), big.NewInt(1))
	if err != nil {
		log.Fatalf("无法部署新的令牌合同: %v", err)
	}
	if err != nil {
		log.Fatalf("无法部署新的令牌合同: %v", err)
	}
	fmt.Printf("合同待定部署: 0x%x\n", address)
	fmt.Printf("交易等待开采: 0x%x\n\n", tx.Hash())
	_, err = bind.WaitDeployed(context.Background(), conn, tx)
	conn.Close()
	return address

}

func (s *Solservice) BlockNumber() string {
	client, err := rpc.Dial("\\\\.\\pipe\\geth.ipc")
	if err != nil {
		fmt.Println("rpc.Dial err", err)
		return ""
	}
	var n string
	err = client.Call(&n, "eth_blockNumber")
	client.Close()
	return n
}

func (s *Solservice) Accounts() []string {
	client, err := rpc.Dial("\\\\.\\pipe\\geth.ipc")
	defer client.Close()
	if err != nil {
		fmt.Println("client.Call err", err)
		return make([]string, 0)
	}
	var account []string
	err = client.Call(&account, "eth_accounts")
	return account
}

func (s *Solservice) GetBalance() string {
	client, err := rpc.Dial("\\\\.\\pipe\\geth.ipc")
	defer client.Close()
	if err != nil {
		fmt.Println("client.Call err", err)
		return ""
	}
	account := s.Accounts()
	var result string
	err = client.Call(&result, "eth_getBalance", account[0], "latest")
	if err != nil {
		fmt.Println("client.Call err", err)
		return ""
	}
	fmt.Println("Balance: ", result)
	return result
}

func (s *Solservice) GetCode() interface{} { //所需内存过大 无法返回，可以在控制台查看。
	client, err := rpc.Dial("\\\\.\\pipe\\geth.ipc")
	defer client.Close()
	if err != nil {
		fmt.Println("client.Call err", err)
		return ""
	}
	var result interface{}
	err = client.Call(&result, "eth_getCode", "0x55c6534fba910ac94f53bb337142b235282cb740", "0x2")
	if err != nil {
		fmt.Println(err)
		return ""
	}
	return result
}

// 创建新用户

func (s *Solservice) NewAccount(passphrase string, sql *repositories.RepositoriesSqlite) {
	rpcDial, err := rpc.Dial("http://127.0.0.1:8545")
	if err != nil {
		log.Fatal("rpcDial", err)
	}
	client := ethclient.NewClient(rpcDial)
	defer client.Close()
	ks := keystore.NewKeyStore("/ethereum/genesis-block/keystore", keystore.StandardScryptN, keystore.StandardScryptP)
	address, _ := ks.NewAccount(passphrase)
	_, err = ks.Export(address, passphrase, "IEC118")
	array := s.Accounts()
	length := len(array)
	HexAddress := array[length-1]
	fmt.Println("HexAddress ", HexAddress)
	sql.InsertAccountsTable(HexAddress, passphrase, length)
	if err != nil {
		panic(err)
	}
}
